পাইথন ফাংশন ওভারলোডিং


213

আমি জানি যে পাইথন পদ্ধতি ওভারলোডিং সমর্থন করে না, তবে আমি এমন একটি সমস্যার মুখোমুখি হয়েছি যা আমি খুব সুন্দর পাইথোনিক উপায়ে সমাধান করতে পারি না।

আমি এমন একটি গেম তৈরি করছি যেখানে কোনও চরিত্রের বিভিন্ন ধরণের বুলেট অঙ্কুর দরকার হয় তবে আমি এই বুলেটগুলি তৈরির জন্য কীভাবে বিভিন্ন ফাংশন লিখব? উদাহরণস্বরূপ ধরুন আমার একটি ফাংশন রয়েছে যা একটি নির্দিষ্ট গতি দিয়ে পয়েন্ট এ থেকে বিতে বুলেট ভ্রমণ করে। আমি এই মত একটি ফাংশন লিখতে হবে:

    def add_bullet(sprite, start, headto, speed):
        ... Code ...

তবে বুলেট তৈরির জন্য আমি অন্যান্য ফাংশন লিখতে চাই:

    def add_bullet(sprite, start, direction, speed):
    def add_bullet(sprite, start, headto, spead, acceleration):
    def add_bullet(sprite, script): # For bullets that are controlled by a script
    def add_bullet(sprite, curve, speed): # for bullets with curved paths
    ... And so on ...

এবং তাই অনেক বৈচিত্র সঙ্গে। এত কিওয়ার্ড আর্গুমেন্ট ব্যবহার না করে এটি করার আরও ভাল উপায় আছে কি এর দ্রুত কৃপণতা পেতে থাকে? প্রতিটি ফাংশন পুনঃনামকরণ করা কারণ আপনি হয় পেতে খুব সুন্দর খারাপ add_bullet1, add_bullet2অথবা add_bullet_with_really_long_name

কিছু উত্তর সম্বোধন করতে:

  1. না আমি বুলেট শ্রেণির শ্রেণিবিন্যাস তৈরি করতে পারি না কারণ এটি খুব ধীর। বুলেট পরিচালনার জন্য আসল কোডটি সিতে রয়েছে এবং আমার ফাংশনগুলি সি এপিআই এর চারপাশে মোড়ক রয়েছে।

  2. আমি কীওয়ার্ড আর্গুমেন্ট সম্পর্কে জানি কিন্তু প্যারামিটারগুলির সমস্ত ধরণের সংমিশ্রণের জন্য পরীক্ষা করা বিরক্তিকর হয়ে উঠছে, তবে ডিফল্ট আর্গুমেন্টগুলি বরাদ্দ করতে সহায়তা করে acceleration=0


5
কেবলমাত্র একটি প্যারামিটারের জন্য কাজ করে, তবে এখানে (অনুসন্ধান ইঞ্জিন থেকে এখানে আসা লোকদের জন্য): ডকস.পিথথন.আর
লিবারিয়ান

1
এটি ডিফল্ট মানগুলির জন্য একটি ভাল জায়গা বলে মনে হচ্ছে। আপনি কিছু না কিছুতে সেট করতে পারেন এবং কেবল তাদের জন্য পরীক্ষা করতে পারেন। অতিরিক্ত বুলিয়ান প্রভাব অবহেলাযোগ্য বলে মনে হচ্ছে
অ্যান্ড্রু স্কট ইভান্স

default value + if + elseসি ++ এর মতোই ব্যবহার করতে হবে। এটি খুবই কিছু বিষয় সি ++ পাইথন চেয়ে ভাল পাঠযোগ্যতা আছে এক ...
Deqing

আমি কোয়ার্গার্স কেন একটি কার্যকর উত্তর নয় তা নিয়ে বিভ্রান্ত। আপনি বলছেন যে আপনি অনেক কীওয়ার্ড আর্গুমেন্ট ব্যবহার করতে চান না কারণ এটি কুরুচিপূর্ণ হয়ে ওঠে ... ঠিক এটিই সমস্যার প্রকৃতি। আপনার যদি অনেক যুক্তি থাকে এবং এটি অগোছালো কারণ আপনি যা আশা করেছিলেন তার চেয়ে অনেক যুক্তি রয়েছে? আপনি কোথাও উল্লেখ না করে অনেক যুক্তি ব্যবহার করতে চান ??? পাইথন মন পাঠক নয়।
ক্যালকুলাস

আমরা জানি না কী ধরণের বস্তুগুলি script, curveহয়, তাদের কি সাধারণ পূর্বপুরুষ থাকে, কোন পদ্ধতি তারা সমর্থন করে। হাঁস-টাইপিংয়ের সাথে, ক্লাস ডিজাইনের জন্য তাদের কী কী পদ্ধতিগুলি সমর্থন করা প্রয়োজন তা নির্ধারণ করা আপনার পক্ষে। সম্ভবত Scriptকিছু ধরণের টাইমস্টেপ-ভিত্তিক কলব্যাক সমর্থন করে (তবে এটি কোন বস্তুটি ফিরে আসবে? সেই টাইমস্টেপের অবস্থান? সেই টাইমস্টেপের ট্র্যাজেক্টোরি?)। সম্ভবত start, direction, speedএবং start, headto, spead, accelerationউভয়ই ট্র্যাজিকোলজির প্রকারের বর্ণনা দেয় তবে পুনরায় গ্রহণযোগ্য শ্রেণীর নকশা করা কীভাবে সেগুলি আনপ্যাক করা যায় এবং কীভাবে এটি প্রক্রিয়া করা যায় তা আপনার উপর নির্ভর করে।
স্মিচি

উত্তর:


144

আপনি যা জিজ্ঞাসা করছেন তাকে একাধিক প্রেরণ বলা হয় । জুলিয়া দেখুন যা পাঠাবে বিভিন্ন ধরনের প্রমান ভাষা উদাহরণ।

যাইহোক, এটি দেখার আগে, আমরা প্রথমে কেন ওভারলোডিং সামলাব আসলে পাইথনে যা চান তা নয়।

কেন ওভারলোডিং হচ্ছে না?

প্রথমত, ওভারলোডিংয়ের ধারণাটি বুঝতে হবে এবং এটি পাইথনের ক্ষেত্রে কেন প্রযোজ্য নয়।

সংকলন সময়ে ডেটা ধরণের বৈষম্য তৈরি করতে পারে এমন ভাষাগুলির সাথে কাজ করার সময়, বিকল্পগুলির মধ্যে নির্বাচন করা সংকলন সময়ে ঘটতে পারে। সংকলন-সময় নির্বাচনের জন্য এই জাতীয় বিকল্প ফাংশন তৈরির কাজটিকে সাধারণত কোনও ফাংশন ওভারলোডিং হিসাবে উল্লেখ করা হয়। ( উইকিপিডিয়া )

পাইথন একটি গতিশীল টাইপিত ভাষা, সুতরাং ওভারলোডিংয়ের ধারণাটি কেবল এটির জন্য প্রযোজ্য নয়। যাইহোক, সমস্ত হারিয়ে যায় না, যেহেতু আমরা রান-টাইমে এই জাতীয় বিকল্পগুলি তৈরি করতে পারি :

প্রোগ্রামিং ল্যাঙ্গুয়েজে ডেটা টাইপ সনাক্তকরণকে রান-টাইম পর্যন্ত স্থগিত করে বিকল্প ফাংশনগুলির মধ্যে নির্বাচন রান-টাইমে হওয়া আবশ্যক, গতিশীলভাবে নির্ধারিত ধরণের ফাংশন আর্গুমেন্টের ভিত্তিতে। যে পদ্ধতিগুলির বিকল্প বাস্তবায়ন এই পদ্ধতিতে নির্বাচিত হয় সেগুলি সাধারণত বহুমাত্রিক হিসাবে উল্লেখ করা হয় । ( উইকিপিডিয়া )

সুতরাং আমাদের পাইথন-বা মাল্টিমেডথগুলি করতে পারার বিকল্প হিসাবে বলা হয়: একাধিক প্রেরণ

একাধিক প্রেরণ

মাল্টিমেডথগুলিকে একাধিক প্রেরণও বলা হয় :

একাধিক প্রেরণ বা মাল্টিম্যাথডস হ'ল কিছু বস্তু-ভিত্তিক প্রোগ্রামিং ভাষার বৈশিষ্ট্য যা কোনও ফাংশন বা পদ্ধতিটিকে তার সময়ের একাধিক যুক্তির رن টাইমের (গতিশীল) ধরণের ভিত্তিতে গতিশীলভাবে প্রেরণ করা যায়। ( উইকিপিডিয়া )

পাইথন বাক্স 1 এর বাইরে এটি সমর্থন করে না , তবে যেমনটি ঘটে, সেখানে একটি বহুভুজ প্যাকেজ রয়েছে যার নাম মাল্টিপ্লেডিস্পাচ যা ঠিক এটি করে।

সমাধান

আপনার পদ্ধতিগুলি বাস্তবায়নের জন্য আমরা কীভাবে গুণিতক প্যাচ 2 প্যাকেজটি ব্যবহার করতে পারি তা এখানে :

>>> from multipledispatch import dispatch
>>> from collections import namedtuple  
>>> from types import *  # we can test for lambda type, e.g.:
>>> type(lambda a: 1) == LambdaType
True

>>> Sprite = namedtuple('Sprite', ['name'])
>>> Point = namedtuple('Point', ['x', 'y'])
>>> Curve = namedtuple('Curve', ['x', 'y', 'z'])
>>> Vector = namedtuple('Vector', ['x','y','z'])

>>> @dispatch(Sprite, Point, Vector, int)
... def add_bullet(sprite, start, direction, speed):
...     print("Called Version 1")
...
>>> @dispatch(Sprite, Point, Point, int, float)
... def add_bullet(sprite, start, headto, speed, acceleration):
...     print("Called version 2")
...
>>> @dispatch(Sprite, LambdaType)
... def add_bullet(sprite, script):
...     print("Called version 3")
...
>>> @dispatch(Sprite, Curve, int)
... def add_bullet(sprite, curve, speed):
...     print("Called version 4")
...

>>> sprite = Sprite('Turtle')
>>> start = Point(1,2)
>>> direction = Vector(1,1,1)
>>> speed = 100 #km/h
>>> acceleration = 5.0 #m/s
>>> script = lambda sprite: sprite.x * 2
>>> curve = Curve(3, 1, 4)
>>> headto = Point(100, 100) # somewhere far away

>>> add_bullet(sprite, start, direction, speed)
Called Version 1

>>> add_bullet(sprite, start, headto, speed, acceleration)
Called version 2

>>> add_bullet(sprite, script)
Called version 3

>>> add_bullet(sprite, curve, speed)
Called version 4

১. পাইথন 3 বর্তমানে একক প্রেরণকে সমর্থন করে
2. বহু-থ্রেডযুক্ত পরিবেশে মাল্টিপ্লেডস্প্যাচ ব্যবহার না করার বিষয়ে খেয়াল রাখুন বা আপনি অদ্ভুত আচরণ পাবেন।


6
মাল্টি-থ্রেড পরিবেশে 'মাল্টিপ্লেডিসপ্যাচ' নিয়ে কী সমস্যা? যেহেতু সার্ভার সাইডের কোডটি সাধারণত বহু-থ্রেডযুক্ত পরিবেশে থাকে! এটি খনন করার চেষ্টা করছি!
ডানজার

7
@ উদনজার এটি থ্রেড-নিরাপদ ছিল না। আমি দুটি ভিন্ন থ্রেড দ্বারা যুক্তিটি সংশোধন করতে দেখলাম (অর্থাত speedফাংশনটির মাঝামাঝি সময়ে পরিবর্তিত হতে পারে যখন অন্য থ্রেডের নিজস্ব মান সেট করে speed) !!! আমার বুঝতে দীর্ঘ সময় লেগেছিল যে এটিই ছিল গ্রন্থাগারই সেই অপরাধী।
অ্যান্ড্রি দ্রোজডিয়ুক

108

পাইথন এটি উপস্থাপন করার সাথে সাথে "মেথড ওভারলোডিং" সমর্থন করে। আসলে, আপনি কেবল যা বর্ণনা করেছেন তা পাইথনে প্রয়োগ করা তুচ্ছ, বিভিন্নভাবে, তবে আমি এর সাথে যাব:

class Character(object):
    # your character __init__ and other methods go here

    def add_bullet(self, sprite=default, start=default, 
                 direction=default, speed=default, accel=default, 
                  curve=default):
        # do stuff with your arguments

উপরের কোড ইন, defaultসেই আর্গুমেন্ট একটি বিশ্বাসযোগ্য ডিফল্ট মান, বা None। তারপরে আপনি যে যুক্তিতে আগ্রহী সেগুলি দিয়ে আপনি সেই পদ্ধতিটি কল করতে পারেন এবং পাইথন ডিফল্ট মানগুলি ব্যবহার করবে।

আপনি এটির মতোও কিছু করতে পারেন:

class Character(object):
    # your character __init__ and other methods go here

    def add_bullet(self, **kwargs):
        # here you can unpack kwargs as (key, values) and
        # do stuff with them, and use some global dictionary
        # to provide default values and ensure that ``key``
        # is a valid argument...

        # do stuff with your arguments

অন্য বিকল্প হ'ল সরাসরি শ্রেণি বা উদাহরণে কাঙ্ক্ষিত ফাংশনটি হুক করা:

def some_implementation(self, arg1, arg2, arg3):
  # implementation
my_class.add_bullet = some_implementation_of_add_bullet

তবুও অন্য উপায় হ'ল বিমূর্ত কারখানার ধরণটি ব্যবহার করা:

class Character(object):
   def __init__(self, bfactory, *args, **kwargs):
       self.bfactory = bfactory
   def add_bullet(self):
       sprite = self.bfactory.sprite()
       speed = self.bfactory.speed()
       # do stuff with your sprite and speed

class pretty_and_fast_factory(object):
    def sprite(self):
       return pretty_sprite
    def speed(self):
       return 10000000000.0

my_character = Character(pretty_and_fast_factory(), a1, a2, kw1=v1, kw2=v2)
my_character.add_bullet() # uses pretty_and_fast_factory

# now, if you have another factory called "ugly_and_slow_factory" 
# you can change it at runtime in python by issuing
my_character.bfactory = ugly_and_slow_factory()

# In the last example you can see abstract factory and "method
# overloading" (as you call it) in action 

107
এগুলি সমস্ত ওভারলোডিংয়ের পরিবর্তে পরিবর্তনশীল যুক্তিগুলির উদাহরণ হিসাবে দেখায়। যেহেতু অতিরিক্ত লোডিং আপনাকে আর্গুমেন্ট হিসাবে বিভিন্ন ধরণের জন্য একই ফাংশন করতে দেয়। যেমন: যোগফল (real_num1, real_num2) এবং যোগফল (কল্পিত_নুম 1, কল্পিত_নুম 2) উভয়ের একই কলিং সিনট্যাক্স থাকবে তবে বাস্তবে ইনপুট হিসাবে 2 টি ভিন্ন ধরণের প্রত্যাশা রয়েছে এবং বাস্তবায়নটি অভ্যন্তরীণভাবেও বদলে যেতে হবে
এফ্রেন

17
আপনি যে উত্তরটি দিয়ে যাবেন তা ব্যবহার করে, আপনি কীভাবে কলারের কাছে উপস্থাপন করবেন যা যুক্তিগুলি এক সাথে বোঝায়? কেবলমাত্র একটি ডিফল্ট মান সহ প্রতিটি যুক্তি গুছিয়ে দেওয়া একই কার্যকারিতা সরবরাহ করতে পারে তবে একটি API এর ক্ষেত্রে এটি খুব কম মার্জিত হয়
গ্রেগ এনিস

6
উপরের কোনওটি ওভারলোডিং নয়, বাস্তবায়নের জন্য প্যারামিটার ইনপুটগুলির সমস্ত সংমিশ্রণ (বা পরামিতি উপেক্ষা) যেমন: if sprite and script and not start and not direction and not speed...এটি কোনও নির্দিষ্ট ক্রিয়াতে রয়েছে তা জানতে হবে know কারণ একটি কলার উপলব্ধ সমস্ত পরামিতি সরবরাহ করে ফাংশনটি কল করতে পারে। অতিরিক্ত লোড করার সময় আপনাকে প্রাসঙ্গিক পরামিতিগুলির সঠিক সেটগুলি সংজ্ঞায়িত করে।
রুই গাভিরেল

5
লোকেরা যখন বলে যে পাইথন পদ্ধতি ওভারলোডিংকে সমর্থন করে এটি খুব মন খারাপ করে। এটা না. আপনি উদ্ধৃতিতে "পদ্ধতি ওভারলোডিং" রাখার বিষয়টি আপনাকে এই সত্যটি সম্পর্কে সচেতন করার ইঙ্গিত দেয়। আপনি এখানে উল্লিখিত মত বেশ কয়েকটি কৌশল দিয়ে অনুরূপ কার্যকারিতা পেতে পারেন। তবে পদ্ধতি ওভারলোডিংয়ের একটি খুব নির্দিষ্ট সংজ্ঞা রয়েছে।
হাওয়ার্ড সোয়াপ

আমি মনে করি উদ্দিষ্ট পয়েন্টটি যখন মেথড ওভারলোডিং পাইথনের কোনও বৈশিষ্ট্য নয়, উপরোক্ত প্রক্রিয়াগুলি সমান প্রভাব অর্জন করতে ব্যবহার করা যেতে পারে।
কাঁচার

93

ফাংশন ওভারলোডিংয়ের জন্য আপনি "নিজের নিজের রোল" সমাধানটি ব্যবহার করতে পারেন। এই একটি মাল্টিমেডাডস সম্পর্কে গাইডো ভ্যান রসমের নিবন্ধ থেকে অনুলিপি করা হয়েছে (কারণ পাইথনে মিমি এবং ওভারলোডিংয়ের মধ্যে সামান্য পার্থক্য রয়েছে):

registry = {}

class MultiMethod(object):
    def __init__(self, name):
        self.name = name
        self.typemap = {}
    def __call__(self, *args):
        types = tuple(arg.__class__ for arg in args) # a generator expression!
        function = self.typemap.get(types)
        if function is None:
            raise TypeError("no match")
        return function(*args)
    def register(self, types, function):
        if types in self.typemap:
            raise TypeError("duplicate registration")
        self.typemap[types] = function


def multimethod(*types):
    def register(function):
        name = function.__name__
        mm = registry.get(name)
        if mm is None:
            mm = registry[name] = MultiMethod(name)
        mm.register(types, function)
        return mm
    return register

ব্যবহার হবে

from multimethods import multimethod
import unittest

# 'overload' makes more sense in this case
overload = multimethod

class Sprite(object):
    pass

class Point(object):
    pass

class Curve(object):
    pass

@overload(Sprite, Point, Direction, int)
def add_bullet(sprite, start, direction, speed):
    # ...

@overload(Sprite, Point, Point, int, int)
def add_bullet(sprite, start, headto, speed, acceleration):
    # ...

@overload(Sprite, str)
def add_bullet(sprite, script):
    # ...

@overload(Sprite, Curve, speed)
def add_bullet(sprite, curve, speed):
    # ...

এই মুহুর্তে সীমাবদ্ধ সীমাবদ্ধতাগুলি হ'ল :

  • পদ্ধতিগুলি সমর্থিত নয়, কেবলমাত্র ফাংশন যা শ্রেণীর সদস্য নয়;
  • উত্তরাধিকার পরিচালনা করা হয় না;
  • kwargs সমর্থিত নয়;
  • নতুন ফাংশনগুলির নিবন্ধকরণ আমদানির সময় করা উচিত থ্রেড-সেফ নয়

6
এই ব্যবহারের ক্ষেত্রে ভাষা প্রসারিত করার জন্য সজ্জাকারীদের জন্য +1।
Eloims

1
+1 কারণ এটি একটি দুর্দান্ত ধারণা (এবং সম্ভবত ওপি'র সাথে কী হওয়া উচিত) --- পাইথনে আমি কোনও বহুমাত্রিক প্রয়োগ কখনও দেখিনি।
ইস্কুয়ালো

39

একটি সম্ভাব্য বিকল্প হিসাবে বিস্তারিত multipledispatch মডিউল ব্যবহার করা: http://matthewrocklin.com/blog/work/2014/02/25/Multiple-Dispatch

এটি করার পরিবর্তে:

def add(self, other):
    if isinstance(other, Foo):
        ...
    elif isinstance(other, Bar):
        ...
    else:
        raise NotImplementedError()

তুমি এটি করতে পারো:

from multipledispatch import dispatch
@dispatch(int, int)
def add(x, y):
    return x + y    

@dispatch(object, object)
def add(x, y):
    return "%s + %s" % (x, y)

ফলে ব্যবহারের সাথে:

>>> add(1, 2)
3

>>> add(1, 'hello')
'1 + hello'

4
কেন এটি বেশি ভোট পায় না? আমি উদাহরণের অভাবের কারণে অনুমান করছি ... আমি মাল্টিপ্লেডিস্পাচ প্যাকেজ দিয়ে ওপির সমস্যার সমাধান কীভাবে বাস্তবায়িত করব তার একটি উদাহরণ সহ একটি উত্তর তৈরি করেছি ।
অ্যান্ড্রি দ্রোজডিউক

19

পাইথনে ৩.৪ যোগ করা হয়েছিল পিইপি -৪৪৩৩। একক প্রেরণ জেনেরিক ফাংশন

এখানে পিইপি থেকে সংক্ষিপ্ত এপিআই বর্ণনা রয়েছে।

জেনেরিক ফাংশনটি সংজ্ঞায়িত করতে, এটি @ সিংসেলিসডপ্যাচ ডেকোরেটর দিয়ে সজ্জিত করুন। নোট করুন যে প্রেরনটি প্রথম আর্গুমেন্টের ধরণে ঘটে। সেই অনুযায়ী আপনার ফাংশন তৈরি করুন:

from functools import singledispatch
@singledispatch
def fun(arg, verbose=False):
    if verbose:
        print("Let me just say,", end=" ")
    print(arg)

ফাংশনে অতিরিক্ত লোড প্রয়োগগুলি যুক্ত করতে জেনেরিক ফাংশনের রেজিস্টার () বৈশিষ্ট্যটি ব্যবহার করুন। এটি একটি সজ্জাকারী, এক ধরণের পরামিতি গ্রহণ করে এবং সেই ধরণের অপারেশন বাস্তবায়িত করে একটি ফাংশন সজ্জিত করে:

@fun.register(int)
def _(arg, verbose=False):
    if verbose:
        print("Strength in numbers, eh?", end=" ")
    print(arg)

@fun.register(list)
def _(arg, verbose=False):
    if verbose:
        print("Enumerate this:")
    for i, elem in enumerate(arg):
        print(i, elem)

11

এই ধরণের আচরণটি সাধারণত বহুত্ববাদ ব্যবহার করে (ওওপি ভাষায়) সমাধান করা হয়। প্রতিটি ধরণের বুলেট এটি কীভাবে ভ্রমণ করে তা জানার জন্য দায়বদ্ধ হবে। এই ক্ষেত্রে:

class Bullet(object):
    def __init__(self):
        self.curve = None
        self.speed = None
        self.acceleration = None
        self.sprite_image = None

class RegularBullet(Bullet):
    def __init__(self):
        super(RegularBullet, self).__init__()
        self.speed = 10

class Grenade(Bullet):
    def __init__(self):
        super(Grenade, self).__init__()
        self.speed = 4
        self.curve = 3.5

add_bullet(Grendade())

def add_bullet(bullet):
    c_function(bullet.speed, bullet.curve, bullet.acceleration, bullet.sprite, bullet.x, bullet.y) 


void c_function(double speed, double curve, double accel, char[] sprite, ...) {
    if (speed != null && ...) regular_bullet(...)
    else if (...) curved_bullet(...)
    //..etc..
}

যে অস্তিত্ব রয়েছে c_function এ যতগুলি আর্গুমেন্ট পাস করুন, তারপরে প্রাথমিক সি ফাংশনে মানগুলির উপর ভিত্তি করে কোন সি ফাংশনটি কল করতে হবে তা নির্ধারণের কাজটি করুন। সুতরাং, পাইথন কেবলমাত্র একটি সি ফাংশন কল করা উচিত। এই এক গ ফাংশন আর্গুমেন্ট তাকান, এবং তারপরে যথাযথভাবে অন্যান্য সি ফাংশন প্রেরণ করতে পারেন।

আপনি মূলত প্রতিটি উপক্লাসকে আলাদা আলাদা ডেটা ধারক হিসাবে ব্যবহার করছেন তবে বেস ক্লাসে সমস্ত সম্ভাব্য যুক্তি সংজ্ঞায়িত করে সাবক্লাসগুলি তাদের সাথে কিছু না করে এড়িয়ে চলা মুক্ত।

যখন নতুন ধরণের বুলেট আসে, আপনি কেবল বেসের আরও একটি সম্পত্তি সংজ্ঞায়িত করতে পারেন, একটি অজগর ফাংশনটি পরিবর্তন করতে পারেন যাতে এটি অতিরিক্ত সম্পত্তি পাস করে এবং একটি সি_ফাংশন যা যুক্তি এবং প্রতিনিধিদের যথাযথভাবে পরীক্ষা করে। আমার ধারণা খুব খারাপ লাগছে না।


1
এটি আমার প্রাথমিক পদ্ধতির ছিল, তবে কার্য সম্পাদনের কারণে আমাকে সি কোডটি পুনরায় লিখতে হয়েছিল
বুলেট

@ বুলেটস, আমি পরামর্শ দেব যে পুরো সি সি ফাংশনগুলি লেখার চেয়ে পারফরম্যান্সের উন্নতির জন্য বিভিন্ন বিকল্পের অনেকগুলি উপস্থিত থাকতে পারে যা সম্ভবত পুরোপুরি কাজ করবে না। উদাহরণস্বরূপ: একটি দৃষ্টান্ত তৈরি করা ব্যয়বহুল হতে পারে, সুতরাং একটি অবজেক্ট পুল বজায় রাখুন। যদিও আমি আপনাকে খুব ধীর বলে মনে করেছি তা না জেনে এটি বলছি। আগ্রহের বাইরে, এই পদ্ধতির সম্পর্কে ঠিক ধীর ছিল কি? সীমানার সি পাশে উল্লেখযোগ্য সময় ব্যয় না করা অবধি পাইথন (নিজেই) আসল সমস্যা।
জোশ স্মিটন

পারফরম্যান্সের উন্নতি করার অন্যান্য উপায়ও থাকতে পারে তবে পাইথনের চেয়ে আমি সি এর চেয়ে অনেক বেশি ভাল। সমস্যাটি গুলিগুলির গতিগুলি গণনা করে এবং যখন তারা স্ক্রিনের সীমা ছাড়িয়ে যায় তখন সনাক্ত করছিল। আমার কাছে বুলেটের অবস্থান গণনা করার pos+v*tএবং তারপরে স্ক্রিনের সীমানা if x > 800এবং এর সাথে তুলনা করার জন্য একটি পদ্ধতি ছিল । এই ফাংশনগুলিকে ফ্রেম প্রতি কয়েকশ বার কল করা অগ্রহণযোগ্যভাবে ধীর হয়ে গেছে। এটি সি
বুলেটস

@ বুলেটস, যথেষ্ট ন্যায্য। আমি এখনও ডেটা এমপ্ল্যাপুলেটিংয়ের জন্য যে পদ্ধতির সাথে গিয়েছিলাম তা ব্যবহার করব। বুলেটের একটি উদাহরণ পাস করুন add_bullet, এবং আপনার প্রয়োজনীয় সমস্ত ক্ষেত্রগুলি বের করুন। আমি আমার উত্তর সম্পাদনা করব।
জোশ স্মিটন

@Bullets: আপনি আপনার সি কার্যকারিতা ও গলি পদ্ধতির জোশ ব্যবহার দ্বারা প্রস্তাবিত একত্রিত করতে পারেন Cython । এটি প্রারম্ভিক বাঁধাইয়ের অনুমতি দেয় যাতে গতির দণ্ড না থাকা উচিত।
jfs


4

হয় সংজ্ঞায় একাধিক কীওয়ার্ড আর্গুমেন্ট ব্যবহার করুন, বা একটি Bulletশ্রেণিবিন্যাস তৈরি করুন যার উদাহরণগুলি ফাংশনে প্রেরণ করা হয়েছে।


আমি দ্বিতীয় পদ্ধতির পরামর্শ দিতে যাচ্ছিলাম: বুলেট সম্পর্কিত বিশদ নির্দিষ্ট করার জন্য কিছু বুলেটপ্যারাম ... ক্লাস করুন।
জন জুইঙ্ক

আপনি এই সম্পর্কে বিস্তারিত বলতে পারেন? আমি বিভিন্ন বুলেট দিয়ে একটি শ্রেণি শ্রেণিবিন্যাস তৈরি করার চেষ্টা করেছি তবে এটি কার্যকর হয় না, কারণ পাইথন খুব ধীর। এটি প্রয়োজনীয় সংখ্যক বুলেটগুলির গতি দ্রুত পর্যাপ্ত পরিমাণে গণনা করতে পারে না, সুতরাং আমাকে সি অংশে লিখতে হয়েছিল সমস্ত অ্যাড_বুললেট রূপগুলি কেবলমাত্র সংশ্লিষ্ট সি ফাংশনটি কল করে।
বুলেট

4

আমি মনে করি যে আপনার প্রাথমিক প্রয়োজনটি পাইথনে কমপক্ষে মাথা ব্যাথা সহ পাইথনে সি / সি ++ এর মতো সিনট্যাক্সের মতো হওয়া উচিত। যদিও আমি আলেকজান্ডার পোলেক্টোভের উত্তর পছন্দ করেছি এটি ক্লাসে কাজ করে না।

নিম্নলিখিত ক্লাসের জন্য কাজ করা উচিত। এটি অ কী-ওয়ার্ড আর্গুমেন্টের সংখ্যা দ্বারা আলাদা করে কাজ করে (তবে প্রকার অনুসারে আলাদা করে সমর্থন করে না):

class TestOverloading(object):
    def overloaded_function(self, *args, **kwargs):
        # Call the function that has the same number of non-keyword arguments.  
        getattr(self, "_overloaded_function_impl_" + str(len(args)))(*args, **kwargs)
    
    def _overloaded_function_impl_3(self, sprite, start, direction, **kwargs):
        print "This is overload 3"
        print "Sprite: %s" % str(sprite)
        print "Start: %s" % str(start)
        print "Direction: %s" % str(direction)
        
    def _overloaded_function_impl_2(self, sprite, script):
        print "This is overload 2"
        print "Sprite: %s" % str(sprite)
        print "Script: "
        print script

এবং এটি সহজভাবে ব্যবহার করা যেতে পারে:

test = TestOverloading()

test.overloaded_function("I'm a Sprite", 0, "Right")
print
test.overloaded_function("I'm another Sprite", "while x == True: print 'hi'")

আউটপুট:

এটি ওভারলোড 3
স্প্রাইট: আমি একটি স্প্রাইট
শুরু: 0
দিকনির্দেশ: ডান

এটি ওভারলোড 2
স্প্রাইট: আমি অন্য স্প্রাইট
স্ক্রিপ্ট:
যখন x == সত্য: 'হাই' মুদ্রণ করুন


4

@overloadপ্রসাধক টাইপ নির্দেশ (PEP 484) সঙ্গে যোগ করা হয়েছিল। যদিও এটি অজগরটির আচরণ পরিবর্তন করে না, এটি কী চলছে তা বুঝতে এবং মাইপির পক্ষে ত্রুটিগুলি সনাক্ত করা সহজ করে তোলে।
দেখুন: ইঙ্গিতগুলি টাইপ করুন এবং পিইপি 484


আপনি কিছু উদাহরণ যোগ করতে পারেন?
জারিত

3

আমি মনে করি Bulletসম্পর্কিত পলিমারফিজমের সাথে কোনও শ্রেণি শ্রেণিবিন্যাস হ'ল উপায়। আপনি একটি মেটাক্লাস ব্যবহার করে বেস ক্লাস কনস্ট্রাক্টরকে কার্যকরভাবে ওভারলোড করতে পারেন যাতে বেস ক্লাসটি কল করলে উপযুক্ত সাবক্লাস অবজেক্ট তৈরি হয়। আমি কী বলতে চাইছি তার সারমর্মটি চিত্রিত করার জন্য নীচে কিছু নমুনা কোড দেওয়া আছে।

আপডেট করা হয়েছে

কোডটি প্রাসঙ্গিক রাখতে পাইথন 2 এবং 3 উভয়ের অধীনে চলতে সংশোধন করা হয়েছে। এটি এমন এক উপায়ে করা হয়েছিল যা পাইথনের স্পষ্টত মেটাগ্লাস সিনট্যাক্স ব্যবহার এড়ানো যায় যা দুটি সংস্করণের মধ্যে পরিবর্তিত হয়।

এই লক্ষ্যটি অর্জনে, ক্লাসের একটি BulletMetaBaseউদাহরণ বেসক্লাস BulletMetaতৈরি করার সময় স্পষ্টভাবে মেটাক্লাসকে কল করে তৈরি করা হয় Bullet( __metaclass__=ক্লাস অ্যাট্রিবিউট ব্যবহার না করে বা metaclassপাইথন সংস্করণের উপর নির্ভর করে কীওয়ার্ড আর্গুমেন্টের মাধ্যমে )।

class BulletMeta(type):
    def __new__(cls, classname, bases, classdict):
        """ Create Bullet class or a subclass of it. """
        classobj = type.__new__(cls, classname, bases, classdict)
        if classname != 'BulletMetaBase':
            if classname == 'Bullet':  # Base class definition?
                classobj.registry = {}  # Initialize subclass registry.
            else:
                try:
                    alias = classdict['alias']
                except KeyError:
                    raise TypeError("Bullet subclass %s has no 'alias'" %
                                    classname)
                if alias in Bullet.registry: # unique?
                    raise TypeError("Bullet subclass %s's alias attribute "
                                    "%r already in use" % (classname, alias))
                # Register subclass under the specified alias.
                classobj.registry[alias] = classobj

        return classobj

    def __call__(cls, alias, *args, **kwargs):
        """ Bullet subclasses instance factory.

            Subclasses should only be instantiated by calls to the base
            class with their subclass' alias as the first arg.
        """
        if cls != Bullet:
            raise TypeError("Bullet subclass %r objects should not to "
                            "be explicitly constructed." % cls.__name__)
        elif alias not in cls.registry: # Bullet subclass?
            raise NotImplementedError("Unknown Bullet subclass %r" %
                                      str(alias))
        # Create designated subclass object (call its __init__ method).
        subclass = cls.registry[alias]
        return type.__call__(subclass, *args, **kwargs)


class Bullet(BulletMeta('BulletMetaBase', (object,), {})):
    # Presumably you'd define some abstract methods that all here
    # that would be supported by all subclasses.
    # These definitions could just raise NotImplementedError() or
    # implement the functionality is some sub-optimal generic way.
    # For example:
    def fire(self, *args, **kwargs):
        raise NotImplementedError(self.__class__.__name__ + ".fire() method")

    # Abstract base class's __init__ should never be called.
    # If subclasses need to call super class's __init__() for some
    # reason then it would need to be implemented.
    def __init__(self, *args, **kwargs):
        raise NotImplementedError("Bullet is an abstract base class")


# Subclass definitions.
class Bullet1(Bullet):
    alias = 'B1'
    def __init__(self, sprite, start, direction, speed):
        print('creating %s object' % self.__class__.__name__)
    def fire(self, trajectory):
        print('Bullet1 object fired with %s trajectory' % trajectory)


class Bullet2(Bullet):
    alias = 'B2'
    def __init__(self, sprite, start, headto, spead, acceleration):
        print('creating %s object' % self.__class__.__name__)


class Bullet3(Bullet):
    alias = 'B3'
    def __init__(self, sprite, script): # script controlled bullets
        print('creating %s object' % self.__class__.__name__)


class Bullet4(Bullet):
    alias = 'B4'
    def __init__(self, sprite, curve, speed): # for bullets with curved paths
        print('creating %s object' % self.__class__.__name__)


class Sprite: pass
class Curve: pass

b1 = Bullet('B1', Sprite(), (10,20,30), 90, 600)
b2 = Bullet('B2', Sprite(), (-30,17,94), (1,-1,-1), 600, 10)
b3 = Bullet('B3', Sprite(), 'bullet42.script')
b4 = Bullet('B4', Sprite(), Curve(), 720)
b1.fire('uniform gravity')
b2.fire('uniform gravity')

আউটপুট:

creating Bullet1 object
creating Bullet2 object
creating Bullet3 object
creating Bullet4 object
Bullet1 object fired with uniform gravity trajectory
Traceback (most recent call last):
  File "python-function-overloading.py", line 93, in <module>
    b2.fire('uniform gravity') # NotImplementedError: Bullet2.fire() method
  File "python-function-overloading.py", line 49, in fire
    raise NotImplementedError(self.__class__.__name__ + ".fire() method")
NotImplementedError: Bullet2.fire() method

হুম এটি এখনও ফাংশনগুলির নাম_এড_ব্লেলেট 1, অ্যাড_বুললেট 2 ইত্যাদি নামকরণ করার এক অভিনব উপায়।
বুলেট

1
@ বুলেটস: সম্ভবত এটি, বা সম্ভবত এটি কারখানার কার্যকারিতা তৈরির কিছুটা বিস্তৃত উপায়। এটি সম্পর্কে একটি দুর্দান্ত বিষয় হ'ল এটি Bulletপ্রতিবার আপনি অন্য সাব টাইপ যুক্ত করার সময় বেস ক্লাস বা ফ্যাক্টরি ফাংশনটি সংশোধন না করে সাবক্লাসের একটি শ্রেণিবিন্যাসকে সমর্থন করে। (অবশ্যই, আপনি যদি সি ++ এর পরিবর্তে সি ব্যবহার করেন তবে আমার ধারণা আপনার কোনও ক্লাস নেই You) আপনি আরও ভাল মেটাগ্লাস তৈরি করতে পারেন যা টাইপ এবং / অথবা সংখ্যার উপর ভিত্তি করে কোন সাবক্লাস তৈরি করতে হবে তা নিজেই নির্ধারণ করতে পারে পাস হওয়া আর্গুমেন্টগুলির (যেমন সি ++ ওভারলোডিং সমর্থন করে)।
মার্টিনিউ

1
এই উত্তরাধিকার ধারণাটিও আমার প্রথম বিকল্প হবে।
ড্যানিয়েল মুলার

3

পাইথন ৩.৮ যোগ করেছে ফান্টটুলস.সেলিংডিসপ্যাচমোথড

একটি পদ্ধতিকে একক-প্রেরণ জেনেরিক ফাংশনে রূপান্তর করুন।

জেনেরিক পদ্ধতিটি সংজ্ঞায়িত করতে, এটি @singledispatchmethod সাজসজ্জা দিয়ে সাজান। নোট করুন যে প্রেরণটি প্রথম অ স্ব-স্ব বা নন-ক্লস আর্গুমেন্টের ধরণের হয়ে যায়, সেই অনুযায়ী আপনার ফাংশনটি তৈরি করুন:

from functools import singledispatchmethod


class Negator:
    @singledispatchmethod
    def neg(self, arg):
        raise NotImplementedError("Cannot negate a")

    @neg.register
    def _(self, arg: int):
        return -arg

    @neg.register
    def _(self, arg: bool):
        return not arg


negator = Negator()
for v in [42, True, "Overloading"]:
    neg = negator.neg(v)
    print(f"{v=}, {neg=}")

আউটপুট

v=42, neg=-42
v=True, neg=False
NotImplementedError: Cannot negate a

@singledispatchmethod অন্যান্য শ্রেণীর সাজসজ্জা যেমন @ ক্লাসমেডোথের সাথে নেস্টিং সমর্থন করে। নোট করুন যে ডিসপ্যাচার.রেজিস্টারের জন্য অনুমতি দেওয়ার জন্য সিঙ্গেলডিসপ্যাচমোথডিয়াল অবশ্যই বাহ্যিক সর্বাধিক সাজসজ্জা করতে হবে। নেগ্রেটর ক্লাসটি এখানে নেগ্র পদ্ধতিতে শ্রেণিবদ্ধ হচ্ছে:

from functools import singledispatchmethod


class Negator:
    @singledispatchmethod
    @staticmethod
    def neg(arg):
        raise NotImplementedError("Cannot negate a")

    @neg.register
    def _(arg: int) -> int:
        return -arg

    @neg.register
    def _(arg: bool) -> bool:
        return not arg


for v in [42, True, "Overloading"]:
    neg = Negator.neg(v)
    print(f"{v=}, {neg=}")

আউটপুট:

v=42, neg=-42
v=True, neg=False
NotImplementedError: Cannot negate a

একই প্যাটার্নটি অনুরূপ অন্যান্য সাজসজ্জার জন্য ব্যবহার করা যেতে পারে: স্ট্যাটিকমেডোথ, বিমূর্ত, এবং অন্যান্য।


2

ডিফল্ট সহ কীওয়ার্ড আর্গুমেন্ট ব্যবহার করুন। যেমন

def add_bullet(sprite, start=default, direction=default, script=default, speed=default):

একটি বাঁকা বুলেট বনাম একটি সরাসরি বুলেট ক্ষেত্রে, আমি দুটি ফাংশন যুক্ত করব: add_bullet_straightএবং add_bullet_curved


2

অজস্র পদ্ধতিতে ওভারলোডিং জটিল is তবে ডিক, তালিকা বা আদিম ভেরিয়েবলগুলি পাস করার ব্যবহার থাকতে পারে।

আমি আমার ব্যবহারের ক্ষেত্রে কিছু চেষ্টা করেছি, এটি পদ্ধতিগুলি ওভারলোড করার জন্য লোকদের বুঝতে এখানে সহায়তা করতে পারে।

আসুন আপনার উদাহরণটি নেওয়া যাক:

বিভিন্ন শ্রেণীর কল পদ্ধতিগুলির সাথে একটি বর্গ ওভারলোড পদ্ধতি।

def add_bullet(sprite=None, start=None, headto=None, spead=None, acceleration=None):

রিমোট ক্লাস থেকে আর্গুমেন্ট পাস:

add_bullet(sprite = 'test', start=Yes,headto={'lat':10.6666,'long':10.6666},accelaration=10.6}

অথবা

add_bullet(sprite = 'test', start=Yes, headto={'lat':10.6666,'long':10.6666},speed=['10','20,'30']}

সুতরাং, পদ্ধতি ওভারলোডিং থেকে তালিকা, অভিধান বা আদিম ভেরিয়েবলের জন্য হ্যান্ডলিং অর্জন করা হচ্ছে।

আপনার কোডগুলির জন্য এটি ব্যবহার করে দেখুন।


2

কেবল একটি সাধারণ সাজসজ্জা

class overload:
    def __init__(self, f):
        self.cases = {}

    def args(self, *args):
        def store_function(f):
            self.cases[tuple(args)] = f
            return self
        return store_function

    def __call__(self, *args):
        function = self.cases[tuple(type(arg) for arg in args)]
        return function(*args)

আপনি এটি ব্যবহার করতে পারেন

@overload
def f():
    pass

@f.args(int, int)
def f(x, y):
    print('two integers')

@f.args(float)
def f(x):
    print('one float')


f(5.5)
f(1, 2)

এটি আপনার ব্যবহারের ক্ষেত্রে অভিযোজিত করতে এটি পরিবর্তন করুন।

ধারণার একটি ব্যাখ্যা

  • ফাংশন প্রেরণ : একই নামে একাধিক ফাংশন রয়েছে। কোনটি বলা উচিত? দুটি কৌশল
  • স্থির / সংকলন-সময় প্রেরণ (যেমন । "ওভারলোডিং" )। আর্গুমেন্টগুলির সংকলন-সময়ের ধরণের ভিত্তিতে কোন ফাংশনটি কল করতে হবে তা স্থির করুন । সমস্ত গতিশীল ভাষায়, কোনও সংকলন-টাইপ টাইপ নেই, সুতরাং সংজ্ঞা দ্বারা ওভারলোডিং অসম্ভব
  • গতিশীল / রান-টাইম প্রেরণ : আর্গুমেন্টের রানটাইম ধরণের ভিত্তিতে কোন ফাংশনটি কল করতে হবে তা স্থির করুন । সমস্ত ওওপি ভাষা এটি করে: একাধিক ক্লাসের একই পদ্ধতি রয়েছে এবং ভাষাটি সিদ্ধান্ত নেয় যে কোনটি self/thisআর্গুমেন্টের ধরণের ভিত্তিতে কল করতে হবে । তবে বেশিরভাগ ভাষাগুলি কেবল এটি thisকেবল যুক্তি দেখায়। উপরের সাজসজ্জারটি ধারণাটি একাধিক পরামিতিগুলিতে প্রসারিত করে।

সাফ করার জন্য, একটি স্থির ভাষা অনুমান করুন এবং কার্যগুলি সংজ্ঞায়িত করুন

void f(Integer x):
    print('integer called')

void f(Float x):
    print('float called')

void f(Number x):
    print('number called')


Number x = new Integer('5')
f(x)
x = new Number('3.14')
f(x)

স্ট্যাটিক প্রেরণের সাথে (ওভারলোডিং) আপনি "নাম্বার" নাম্বারটি দুটি বার দেখতে পাবেন, কারণ xএটি হিসাবে ঘোষণা করা হয়েছে Number, এবং এটিই সমস্ত ওভারলোডিং যত্নশীল। ডায়নামিক প্রেরণের সাথে আপনি দেখতে পাবেন "পূর্ণসংখ্যার নামে পরিচিত, ভাসমান বলা হয়", কারণ xফাংশনটি বলা হওয়ার সময়ে সেগুলি প্রকৃত ধরণের ।


এই উদাহরণটি অত্যন্ত গুরুত্বপূর্ণভাবে বোঝায় না যে কোন পদ্ধতিটি শুরু হয়েছিলx গতিশীল প্রেরণের জন্য , বা কোন ক্রমে উভয় পদ্ধতি স্থিতিশীল প্রেরণের জন্য আহ্বান করেছে। আপনি মুদ্রণ বিবৃতি print('number called for Integer')ইত্যাদি সম্পাদনা করার পরামর্শ দিচ্ছেন
স্মিচি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.