खोज…


परिचय

पायथन न केवल एक लोकप्रिय स्क्रिप्टिंग भाषा के रूप में खुद को पेश करता है, बल्कि ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग प्रतिमान का भी समर्थन करता है। कक्षाएं डेटा का वर्णन करती हैं और उस डेटा को हेरफेर करने के तरीके प्रदान करती हैं, सभी एक ही वस्तु के तहत शामिल हैं। इसके अलावा, कक्षाएं डेटा के अमूर्त अभ्यावेदन से ठोस कार्यान्वयन विवरण को अलग करके अमूर्तता की अनुमति देती हैं।

कोड का उपयोग करने वाली कक्षाएं आमतौर पर पढ़ने, समझने और बनाए रखने में आसान होती हैं।

मूल वंशानुक्रम

पायथन में वंशानुक्रम जावा, सी ++ आदि जैसी अन्य वस्तु उन्मुख भाषाओं में उपयोग किए जाने वाले समान विचारों पर आधारित है। एक नया वर्ग मौजूदा वर्ग से निम्नानुसार प्राप्त किया जा सकता है।

class BaseClass(object):
    pass

class DerivedClass(BaseClass):
    pass

BaseClass पहले से ही विद्यमान (पैरेंट) वर्ग है, और DerivedClass नई (बच्चे) वर्ग कि inherits (या उपवर्ग) से जिम्मेदार बताते है BaseClassनोट : पायथन 2.2 के रूप में, सभी वर्ग स्पष्ट रूप से object क्लास से विरासत में मिलते हैं , जो सभी प्रकारों के लिए बेस क्लास है।

हम नीचे दिए गए उदाहरण में एक मूल Rectangle वर्ग को परिभाषित करते हैं, जो कि object से अंतर्निहित है:

class Rectangle():
    def __init__(self, w, h):
        self.w = w
        self.h = h
    
    def area(self):
        return self.w * self.h
        
    def perimeter(self):
        return 2 * (self.w + self.h)

Rectangle वर्ग एक निर्णायक के लिए एक आधार वर्ग के रूप में इस्तेमाल किया जा सकता Square के रूप में एक वर्ग आयत के एक विशेष मामला है, वर्ग।

class Square(Rectangle):
    def __init__(self, s):
        # call parent constructor, w and h are both s
        super(Square, self).__init__(s, s)
        self.s = s

Square वर्ग स्वचालित रूप से Rectangle वर्ग के साथ-साथ ऑब्जेक्ट क्लास की सभी विशेषताओं को प्राप्त करेगा। super() का उपयोग Rectangle वर्ग के __init__() पद्धति को कॉल करने के लिए किया जाता है, अनिवार्य रूप से आधार वर्ग के किसी भी ओवरराइड विधि को कॉल करने के लिए। नोट : पायथन 3 में, super() को तर्कों की आवश्यकता नहीं है।

व्युत्पन्न वर्ग की वस्तुएं अपने आधार वर्गों की विशेषताओं को एक्सेस और संशोधित कर सकती हैं:

r.area()
# Output: 12
r.perimeter()  
# Output: 14

s.area()
# Output: 4
s.perimeter()
# Output: 8

अंतर्निहित कार्य जो विरासत के साथ काम करते हैं

issubclass(DerivedClass, BaseClass) : रिटर्न True , तो DerivedClass का एक उपवर्ग है BaseClass

isinstance(s, Class) : रिटर्न True , तो रों का एक उदाहरण है Class या के व्युत्पन्न वर्ग के किसी भी Class

# subclass check        
issubclass(Square, Rectangle)
# Output: True

# instantiate
r = Rectangle(3, 4)
s = Square(2)

isinstance(r, Rectangle)  
# Output: True
isinstance(r, Square)
# Output: False
# A rectangle is not a square

isinstance(s, Rectangle)
# Output: True
# A square is a rectangle
isinstance(s, Square)
# Output: True

वर्ग और उदाहरण चर

इंस्टेंस चर प्रत्येक उदाहरण के लिए अद्वितीय होते हैं, जबकि कक्षा चर सभी उदाहरणों द्वारा साझा किए जाते हैं।

class C:
    x = 2  # class variable

    def __init__(self, y):
        self.y = y  # instance variable

C.x
# 2
C.y
# AttributeError: type object 'C' has no attribute 'y'

c1 = C(3)
c1.x
# 2
c1.y
# 3

c2 = C(4)
c2.x
# 2
c2.y
# 4

इस वर्ग के उदाहरणों पर कक्षा चर को एक्सेस किया जा सकता है, लेकिन वर्ग विशेषता को असाइन करने से एक आवृत्ति चर पैदा होगा जो वर्ग चर को छाया देता है

c2.x = 4
c2.x
# 4
C.x
# 2

ध्यान दें कि इंस्टेंसेस से क्लास वेरिएबल को म्यूट करने से कुछ अप्रत्याशित परिणाम हो सकते हैं।

class D:
    x = []
    def __init__(self, item):
        self.x.append(item)  # note that this is not an assigment!

d1 = D(1)
d2 = D(2)

d1.x
# [1, 2]
d2.x
# [1, 2]
D.x
# [1, 2]

बाउंड, अनबाउंड और स्टैटिक तरीके

पायथन 3 में बाध्य और अनबाउंड तरीकों का विचार हटा दिया गया था। पायथन 3 में जब आप किसी वर्ग के भीतर एक विधि की घोषणा करते हैं, तो आप एक def कीवर्ड का उपयोग कर रहे हैं, इस प्रकार एक फंक्शन ऑब्जेक्ट का निर्माण होता है। यह एक नियमित कार्य है, और आसपास का वर्ग इसके नामस्थान के रूप में काम करता है। निम्न उदाहरण में हम प्रणाली की घोषणा f वर्ग के भीतर A है, और यह एक समारोह हो जाता है Af :

अजगर 3.x 3.0
class A(object):
    def f(self, x):
        return 2 * x
A.f
# <function A.f at ...>  (in Python 3.x)

पायथन 2 में व्यवहार भिन्न था: वर्ग के भीतर फ़ंक्शन ऑब्जेक्ट्स को स्पष्ट रूप से टाइप instancemethod की वस्तुओं के साथ बदल दिया गया था, जिन्हें अनबाउंड तरीके कहा जाता था क्योंकि वे किसी विशेष वर्ग के उदाहरण के लिए बाध्य नहीं थे। .__func__ संपत्ति का उपयोग करके अंतर्निहित फ़ंक्शन तक पहुंचना संभव था।

पायथन 2.x 2.3
A.f
# <unbound method A.f>   (in Python 2.x)
A.f.__class__
# <type 'instancemethod'>
A.f.__func__
# <function f at ...>

बाद के व्यवहारों को निरीक्षण द्वारा पुष्टि की जाती है - विधियों को पायथन 3 में कार्यों के रूप में मान्यता दी जाती है, जबकि पायथन 2 में भेद को बरकरार रखा जाता है।

अजगर 3.x 3.0
import inspect

inspect.isfunction(A.f)
# True
inspect.ismethod(A.f)
# False
पायथन 2.x 2.3
import inspect

inspect.isfunction(A.f)
# False
inspect.ismethod(A.f)
# True

पायथन फ़ंक्शन / विधि के दोनों संस्करणों में Af को सीधे कहा जा सकता है, बशर्ते कि आप पहले तर्क के रूप में कक्षा A का एक उदाहरण दें।

A.f(1, 7)
# Python 2: TypeError: unbound method f() must be called with
#                      A instance as first argument (got int instance instead) 
# Python 3: 14   
a = A()
A.f(a, 20)
# Python 2 & 3: 40

अब मान लीजिए कि a वर्ग का एक उदाहरण है A , क्या है af तो? ठीक है, intuitively इस एक ही विधि का होना चाहिए f वर्ग के A , केवल यह किसी भी तरह "पता" चाहिए कि यह वस्तु के लिए लागू किया गया था a - अजगर में इस विधि के लिए बाध्य कर कहा जाता है a

बुनियादी तथ्य विवरण इस प्रकार हैं: लेखन af का आह्वान जादू __getattribute__ की विधि a है, जो पहली जाँच करता है कि a एक विशेषता नामक f (यह नहीं है), तो चेक के वर्ग A है कि क्या यह एक तरीका है इस तरह के एक नाम के साथ शामिल (यह है), और एक नई वस्तु बनाता m प्रकार की method जो मूल के संदर्भ में है Af में m.__func__ , और वस्तु के लिए एक संदर्भ a में m.__self__ । जब इस ऑब्जेक्ट को एक फ़ंक्शन के रूप में कहा जाता है, तो यह बस निम्नलिखित करता है: m(...) => m.__func__(m.__self__, ...) । इस प्रकार इस वस्तु को एक बाध्य विधि कहा जाता है क्योंकि जब आह्वान किया जाता है तो वह उस वस्तु की आपूर्ति करना जानती है जो पहले तर्क के रूप में बंधी थी। (ये बातें पाइथन 2 और 3 में उसी तरह काम करती हैं)।

a = A()
a.f
# <bound method A.f of <__main__.A object at ...>>
a.f(2)
# 4

# Note: the bound method object a.f is recreated *every time* you call it:
a.f is a.f  # False
# As a performance optimization you can store the bound method in the object's
# __dict__, in which case the method object will remain fixed:
a.f = a.f
a.f is a.f  # True

अंत में, पायथन में वर्ग विधियाँ और स्थैतिक विधियाँ हैं - विशेष प्रकार की विधियाँ। क्लास मेथड्स रेगुलर मेथड्स की तरह ही काम करते हैं, सिवाय इसके कि जब किसी ऑब्जेक्ट पर इनवेस्ट किया जाता है तो वे ऑब्जेक्ट के बजाय ऑब्जेक्ट के क्लास से बंधते हैं। इस प्रकार m.__self__ = type(a) । जब आप इस तरह के बाध्य विधि कॉल, यह वर्ग से गुजरता a पहले तर्क के रूप में। स्टैटिक विधियां और भी सरल हैं: वे किसी भी चीज को बांधते नहीं हैं, और बस बिना किसी परिवर्तन के अंतर्निहित फ़ंक्शन को वापस करते हैं।

class D(object):
    multiplier = 2

    @classmethod
    def f(cls, x):
        return cls.multiplier * x

    @staticmethod
    def g(name):
        print("Hello, %s" % name)

D.f
# <bound method type.f of <class '__main__.D'>>
D.f(12)
# 24
D.g
# <function D.g at ...>
D.g("world")
# Hello, world

ध्यान दें कि वर्ग विधियाँ वर्ग तक पहुँच जाने पर भी बाध्य होती हैं:

d = D()
d.multiplier = 1337
(D.multiplier, d.multiplier)
# (2, 1337)
d.f
# <bound method D.f of <class '__main__.D'>>
d.f(10)
# 20

यह ध्यान देने योग्य है कि सबसे निचले स्तर पर, फ़ंक्शन, विधियाँ, स्टेटमिथोड्स, आदि वास्तव में ऐसे डिस्क्रिप्टर हैं जो __get__ , __set __ और वैकल्पिक रूप से __del__ विशेष विधियों का आह्वान करते हैं। Classmethods और staticmethods के बारे में अधिक जानकारी के लिए:

नई शैली बनाम पुरानी शैली की कक्षाएं

पायथन 2.x 2.2.0

कक्षाओं और प्रकारों को एकजुट करने के लिए पायथन 2.2 में नई शैली की कक्षाएं शुरू की गईं। उन्हें शीर्ष-स्तरीय object प्रकार से विरासत में मिला है। एक नई शैली की कक्षा एक उपयोगकर्ता-परिभाषित प्रकार है , और बिल्ट-इन प्रकारों के समान है।

# new-style class
class New(object):
    pass

# new-style instance
new = New()

new.__class__
# <class '__main__.New'>
type(new)
# <class '__main__.New'>
issubclass(New, object)
# True

पुरानी शैली की कक्षाएं object से विरासत में नहीं मिलती हैं। पुरानी शैली के उदाहरण हमेशा अंतर्निहित instance प्रकार के साथ कार्यान्वित किए जाते हैं।

# old-style class
class Old:
    pass

# old-style instance
old = Old()

old.__class__
# <class __main__.Old at ...>
type(old)
# <type 'instance'>
issubclass(Old, object)
# False
अजगर 3.x 3.0.0

पायथन 3 में, पुरानी शैली की कक्षाएं हटा दी गईं।

पायथन 3 में नई-शैली की कक्षाएं स्पष्ट रूप से object से विरासत में मिली हैं, इसलिए अब MyClass(object) को निर्दिष्ट करने की कोई आवश्यकता नहीं है।

class MyClass:
    pass

my_inst = MyClass()

type(my_inst)
# <class '__main__.MyClass'>
my_inst.__class__
# <class '__main__.MyClass'>
issubclass(MyClass, object)
# True

उदाहरण चर के लिए डिफ़ॉल्ट मान

यदि चर में एक अपरिवर्तनीय प्रकार (जैसे एक स्ट्रिंग) का मान होता है, तो इस तरह एक डिफ़ॉल्ट मान निर्दिष्ट करना ठीक है

class Rectangle(object):
    def __init__(self, width, height, color='blue'):
        self.width = width
        self.height = height
        self.color = color
    
    def area(self):
        return self.width  * self.height 

# Create some instances of the class
default_rectangle = Rectangle(2, 3)
print(default_rectangle.color) # blue

red_rectangle = Rectangle(2, 3, 'red')
print(red_rectangle.color) # red

निर्माण में सूचियों जैसे उत्परिवर्तित वस्तुओं को आरम्भ करते समय सावधानी बरतने की आवश्यकता है। निम्नलिखित उदाहरण पर विचार करें:

class Rectangle2D(object):
    def __init__(self, width, height, pos=[0,0], color='blue'):  
        self.width = width
        self.height = height
        self.pos = pos
        self.color = color

r1 = Rectangle2D(5,3)
r2 = Rectangle2D(7,8)
r1.pos[0] = 4
r1.pos # [4, 0]
r2.pos # [4, 0] r2's pos has changed as well

यह व्यवहार इस तथ्य के कारण होता है कि पायथन डिफ़ॉल्ट पैरामीटर फ़ंक्शन निष्पादन में बाध्य हैं और फ़ंक्शन घोषणा में नहीं। डिफ़ॉल्ट आवृत्ति चर प्राप्त करने के लिए जिसे उदाहरणों के बीच साझा नहीं किया जाता है, किसी को इस तरह एक निर्माण का उपयोग करना चाहिए:

class Rectangle2D(object):
    def __init__(self, width, height, pos=None, color='blue'):  
        self.width = width
        self.height = height
        self.pos = pos or [0, 0] # default value is [0, 0]
        self.color = color

r1 = Rectangle2D(5,3)
r2 = Rectangle2D(7,8)
r1.pos[0] = 4
r1.pos # [4, 0]
r2.pos # [0, 0] r2's pos hasn't changed 

म्यूटेबल डिफॉल्ट आर्ग्युमेंट्स और "लिस्ट एस्टनमेंट" और म्यूटेबल डिफॉल्ट आर्ग्युमेंट भी देखें

एकाधिक वंशानुक्रम

पायथन सी 3 रैखिककरण एल्गोरिथ्म का उपयोग उस क्रम को निर्धारित करने के लिए करता है जिसमें विधि सहित, वर्ग विशेषताओं को हल करना है। इसे विधि समाधान आदेश (MRO) के रूप में जाना जाता है।

यहाँ एक सरल उदाहरण है:

class Foo(object):
    foo = 'attr foo of Foo'
    

class Bar(object):
    foo = 'attr foo of Bar' # we won't see this.
    bar = 'attr bar of Bar'

class FooBar(Foo, Bar):
    foobar = 'attr foobar of FooBar'

अब अगर हम FooBar को तत्काल करते हैं, अगर हम foo विशेषता को देखते हैं, तो हम देखते हैं कि Foo की विशेषता पहले पाई गई है

fb = FooBar()

तथा

>>> fb.foo
'attr foo of Foo'

यहाँ FooBar का MRO है:

>>> FooBar.mro()
[<class '__main__.FooBar'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <type 'object'>]

यह बस कहा जा सकता है कि पायथन का एमआरओ एल्गोरिदम है

  1. जब तक गहराई पहले (जैसे FooBar फिर Foo )
  2. एक साझा माता-पिता ( object ) एक बच्चे ( Bar ) और द्वारा अवरुद्ध है
  3. कोई परिपत्र रिश्तों की अनुमति नहीं है।

उदाहरण के लिए, बार FooBar से वारिस नहीं हो सकता, जबकि FooBar बार से विरासत में मिलता है।

पायथन में एक व्यापक उदाहरण के लिए, विकिपीडिया प्रविष्टि देखें।

विरासत में एक और शक्तिशाली विशेषता super । सुपर पैरेंट क्लासेस के फीचर्स ला सकता है।

class Foo(object):
    def foo_method(self):
        print "foo Method"

class Bar(object):
    def bar_method(self):
        print "bar Method"

class FooBar(Foo, Bar):
    def foo_method(self):
        super(FooBar, self).foo_method()

वर्ग की init पद्धति के साथ एकाधिक वंशानुक्रम, जब प्रत्येक वर्ग के पास init पद्धति होती है, तब हम कई ineritance के लिए प्रयास करते हैं, तब केवल init पद्धति को वर्ग कहा जाता है, जो पहले विरासत में मिली है।

उदाहरण के लिए केवल फू क्लास इनिट विधि जिसे बार क्लास इनिट कहा जाता है उसे नहीं बुलाया जाता है

    class Foo(object):
        def __init__(self):
            print "foo init"

    class Bar(object):
        def __init__(self):
            print "bar init"

    class FooBar(Foo, Bar):
        def __init__(self):
            print "foobar init"
            super(FooBar, self).__init__()

    a = FooBar()

आउटपुट:

    foobar init
    foo init

लेकिन इसका मतलब यह नहीं है कि बार वर्ग विरासत में नहीं है। अंतिम फूबर वर्ग का उदाहरण भी बार वर्ग और फू वर्ग का उदाहरण है।

print isinstance(a,FooBar)
print isinstance(a,Foo)
print isinstance(a,Bar) 

आउटपुट:

True
True
True

डिस्क्रिप्टर्स और डॉटेड लुकअप

डिस्क्रिप्टर्स वे ऑब्जेक्ट्स होते हैं जो (आमतौर पर) कक्षाओं के गुण होते हैं और जिनमें __get__ , __set__ , या __delete__ विशेष विधियां होती हैं।

डेटा डिस्क्रिप्टर्स में __set__ , या __delete__ कोई भी है

ये एक उदाहरण पर बिंदीदार लुक को नियंत्रित कर सकते हैं, और फ़ंक्शंस, staticmethod , classmethod और property को लागू करने के लिए उपयोग किया जाता है। एक बिंदीदार देखने (जैसे उदाहरण foo वर्ग के Foo विशेषता को देख bar - यानी foo.bar ) निम्नलिखित कलन विधि का उपयोग करता है:

  1. bar को कक्षा में देखा जाता है, Foo । यदि यह वहाँ है और यह एक डेटा डिस्क्रिप्टर है , तो डेटा डिस्क्रिप्टर का उपयोग किया जाता है। इस तरह property एक उदाहरण में डेटा तक पहुंच को नियंत्रित करने में सक्षम है, और उदाहरण इसे ओवरराइड नहीं कर सकते। यदि कोई डेटा डिस्क्रिप्टर नहीं है, तो

  2. bar को उदाहरण में देखा जाता है __dict__ । यही कारण है कि हम एक उदाहरण से बिंदीदार लुकअप के साथ बुलाए गए तरीकों को ओवरराइड या ब्लॉक कर सकते हैं। यदि bar उदाहरण में मौजूद है, तो इसका उपयोग किया जाता है। यदि नहीं, तो हम

  3. bar लिए कक्षा Foo । यदि यह एक डिस्क्रिप्टर है , तो डिस्क्रिप्टर प्रोटोकॉल का उपयोग किया जाता है। यह इस प्रकार है कि फ़ंक्शन (इस संदर्भ में, अनबाउंड तरीके), classmethod , और staticmethod को लागू किया जाता है। इसके बजाय यह केवल वस्तु को वहां लौटाता है, या एक AttributeError

क्लास के तरीके: अल्टरनेटिव इनिशियलाइज़र

कक्षा विधियाँ कक्षाओं के उदाहरण बनाने के लिए वैकल्पिक तरीके प्रस्तुत करती हैं। उदाहरण के लिए, आइए एक उदाहरण देखें।

मान लीजिए कि हमारे पास एक अपेक्षाकृत सरल Person वर्ग है:

class Person(object):

    def __init__(self, first_name, last_name, age):
        self.first_name = first_name
        self.last_name = last_name
        self.age = age
        self.full_name = first_name + " " + last_name
    
    def greet(self):
        print("Hello, my name is " + self.full_name + ".")

इस वर्ग के उदाहरणों का निर्माण करने का तरीका आसान हो सकता है, पहले और अंतिम नाम के बजाय अलग नाम निर्दिष्ट करें। ऐसा करने का एक तरीका यह होगा कि last_name एक वैकल्पिक पैरामीटर हो, और यह मानते हुए कि यदि यह नहीं दिया गया है, तो हमने पूरा नाम इसमें दिया:

class Person(object):

    def __init__(self, first_name, age, last_name=None):
        if last_name is None:
            self.first_name, self.last_name = first_name.split(" ", 2)
        else:
            self.first_name = first_name
            self.last_name = last_name
        
        self.full_name = self.first_name + " " + self.last_name
        self.age = age

    def greet(self):
        print("Hello, my name is " + self.full_name + ".")

हालांकि, इस बिट कोड के साथ दो मुख्य समस्याएं हैं:

  1. पैरामीटर first_name और last_name अब भ्रामक हैं, क्योंकि आप first_name लिए पूरा नाम दर्ज कर सकते हैं। इसके अलावा, अगर इस तरह के लचीलेपन के अधिक मामले और / या अधिक पैरामीटर हैं, तो / elif / अन्यथा ब्रांचिंग कष्टप्रद तेजी ला सकती है।

  2. बहुत महत्वपूर्ण नहीं है, लेकिन फिर भी यह इंगित करने के लायक है: क्या होगा अगर last_name None , लेकिन first_name दो या दो से अधिक चीजों को अंतरिक्ष में विभाजित नहीं करता है? हमारे पास अभी तक इनपुट सत्यापन और / या अपवाद हैंडलिंग की एक और परत है ...

कक्षा के तरीके दर्ज करें। एकल from_full_name होने के बजाय, हम एक अलग from_full_name , जिसे from_full_name कहा जाता है, और इसे (बिल्ट-इन) classmethod डेकोरेटर से classmethod

class Person(object):

    def __init__(self, first_name, last_name, age):
        self.first_name = first_name
        self.last_name = last_name
        self.age = age
        self.full_name = first_name + " " + last_name
    
    @classmethod
    def from_full_name(cls, name, age):
        if " " not in name:
            raise ValueError
        first_name, last_name = name.split(" ", 2)
        return cls(first_name, last_name, age)
    
    def greet(self):
        print("Hello, my name is " + self.full_name + ".")

सूचना cls के बजाय self के लिए सबसे पहले तर्क के रूप में from_full_name । कक्षा विधियां समग्र वर्ग पर लागू होती हैं, किसी दिए गए वर्ग का उदाहरण नहीं (जो कि आमतौर पर self को दर्शाता है)। तो, अगर cls हमारे है Person वर्ग है, तो से दिए गए मान from_full_name वर्ग विधि है Person(first_name, last_name, age) है, जो का उपयोग करता है Person की __init__ का एक उदाहरण बनाने के लिए Person वर्ग। विशेष रूप से, यदि हमें एक Person का उप- Employee बनाना है, तो from_full_name Employee वर्ग में भी काम करेगा।

यह दिखाने के लिए कि यह उम्मीद के मुताबिक काम करता है, आइए __init__ में शाखा के बिना एक से अधिक तरीकों से Person उदाहरण बनाएं:

In [2]: bob = Person("Bob", "Bobberson", 42)

In [3]: alice = Person.from_full_name("Alice Henderson", 31)

In [4]: bob.greet()
Hello, my name is Bob Bobberson.

In [5]: alice.greet()
Hello, my name is Alice Henderson.

अन्य संदर्भ:

वर्ग रचना

कक्षा रचना वस्तुओं के बीच स्पष्ट संबंधों की अनुमति देती है। इस उदाहरण में, लोग उन शहरों में रहते हैं जो देशों के हैं। रचना लोगों को उनके देश में रहने वाले सभी लोगों की संख्या तक पहुंचने की अनुमति देती है:

class Country(object):
    def __init__(self):
        self.cities=[]
        
    def addCity(self,city):
        self.cities.append(city)
        

class City(object):
    def __init__(self, numPeople):
        self.people = []
        self.numPeople = numPeople
        
        
    def addPerson(self, person):
        self.people.append(person)
    
    def join_country(self,country):
        self.country = country
        country.addCity(self)
        
        for i in range(self.numPeople):
                person(i).join_city(self)
  

class Person(object):
    def __init__(self, ID):
        self.ID=ID

    def join_city(self, city):
        self.city = city
        city.addPerson(self)
        
    def people_in_my_country(self):
        x= sum([len(c.people) for c in self.city.country.cities])
        return x
        
US=Country()
NYC=City(10).join_country(US)
SF=City(5).join_country(US)

print(US.cities[0].people[0].people_in_my_country())

# 15

बंदर पटकना

इस मामले में, "मंकी पैचिंग" का अर्थ है एक वर्ग के लिए एक नया चर या तरीका जोड़ना जो परिभाषित होने के बाद। उदाहरण के लिए, मान लें कि हमने क्लास A को परिभाषित किया है

class A(object):
    def __init__(self, num):
        self.num = num

    def __add__(self, other):
        return A(self.num + other.num)

लेकिन अब हम बाद में कोड में एक और फ़ंक्शन जोड़ना चाहते हैं। मान लीजिए कि यह फ़ंक्शन निम्नानुसार है।

def get_num(self):
    return self.num

लेकिन हम इसे A में A विधि के रूप में कैसे जोड़ते हैं? यह सरल है कि हम केवल उस कार्य को असाइनमेंट स्टेटमेंट के साथ A में रखें।

A.get_num = get_num

यह काम क्यों करता है? क्योंकि फ़ंक्शंस किसी अन्य ऑब्जेक्ट की तरह ऑब्जेक्ट हैं, और विधियाँ फ़ंक्शंस हैं जो क्लास से संबंधित हैं।

फ़ंक्शन get_num सभी मौजूदा (पहले से निर्मित) और साथ ही A के नए उदाहरणों के लिए उपलब्ध होगा

ये परिवर्धन स्वचालित रूप से उस वर्ग (या उसके उपवर्ग) के सभी उदाहरणों पर उपलब्ध हैं। उदाहरण के लिए:

foo = A(42)

A.get_num = get_num

bar = A(6);

foo.get_num() # 42

bar.get_num() # 6

ध्यान दें, कुछ अन्य भाषाओं के विपरीत, यह तकनीक कुछ अंतर्निहित प्रकारों के लिए काम नहीं करती है, और इसे अच्छी शैली नहीं माना जाता है।

सभी कक्षा सदस्यों की सूची बनाना

dir() फ़ंक्शन का उपयोग किसी वर्ग के सदस्यों की सूची प्राप्त करने के लिए किया जा सकता है:

dir(Class)

उदाहरण के लिए:

>>> dir(list)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

केवल "गैर-जादू" सदस्यों के लिए देखना आम है। यह एक सरल समझ का उपयोग करके किया जा सकता है जो सदस्यों को __ शुरू न होने वाले नामों की सूची देता है:

>>> [m for m in dir(list) if not m.startswith('__')]
['append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

चेतावनियां:

कक्षाएं एक __dir__() विधि को परिभाषित कर सकती हैं। यदि वह विधि dir() कॉलिंग में मौजूद है तो __dir__() कॉल करेगा, अन्यथा पायथन वर्ग के सदस्यों की सूची बनाने का प्रयास करेगा। इसका मतलब है कि dir फ़ंक्शन के अप्रत्याशित परिणाम हो सकते हैं। आधिकारिक अजगर प्रलेखन से महत्व के दो उद्धरण:

यदि ऑब्जेक्ट डीआईआर () प्रदान नहीं करता है, तो फ़ंक्शन ऑब्जेक्ट के तानाशाह विशेषता, यदि परिभाषित किया गया है, और इसके प्रकार ऑब्जेक्ट से जानकारी इकट्ठा करने की पूरी कोशिश करता है। परिणामी सूची आवश्यक रूप से पूरी नहीं होती है, और जब ऑब्जेक्ट कस्टम गेटटार () हो तो गलत हो सकता है।

नोट: क्योंकि dir () को मुख्य रूप से इंटरेक्टिव प्रॉम्प्ट पर उपयोग करने के लिए एक सुविधा के रूप में आपूर्ति की जाती है, यह नामों की एक दिलचस्प सेट की आपूर्ति करने की कोशिश करता है जितना कि यह एक कठोर या लगातार परिभाषित नामों की आपूर्ति करने की कोशिश करता है, और इसका विस्तृत व्यवहार बदल सकता है विज्ञप्ति। उदाहरण के लिए, मेटाक्लास विशेषताएँ परिणाम सूची में नहीं होती हैं जब तर्क एक वर्ग होता है।

कक्षाओं का परिचय

एक वर्ग, एक टेम्पलेट के रूप में कार्य करता है जो किसी विशेष वस्तु की बुनियादी विशेषताओं को परिभाषित करता है। यहाँ एक उदाहरण है:

class Person(object):
     """A simple class."""                            # docstring
     species = "Homo Sapiens"                         # class attribute

     def __init__(self, name):                        # special method
         """This is the initializer. It's a special
         method (see below).
         """
         self.name = name                             # instance attribute

     def __str__(self):                               # special method
         """This method is run when Python tries 
         to cast the object to a string. Return 
         this string when using print(), etc.
         """
         return self.name

     def rename(self, renamed):                       # regular method
         """Reassign and print the name attribute."""
         self.name = renamed
         print("Now my name is {}".format(self.name))

उपरोक्त उदाहरण को देखते समय कुछ बातें ध्यान देने योग्य हैं।

  1. वर्ग विशेषताओं (डेटा) और विधियों (कार्यों) से बना है।
  2. विशेषताएँ और विधियाँ बस सामान्य चर और कार्यों के रूप में परिभाषित की जाती हैं।
  3. जैसा कि संबंधित __init__() में उल्लेख किया गया है, __init__() विधि को इनिशियलाइज़र कहा जाता है । यह अन्य ऑब्जेक्ट ओरिएंटेड भाषाओं में कंस्ट्रक्टर के बराबर है, और वह विधि है जो पहली बार तब चलती है जब आप एक नई ऑब्जेक्ट, या क्लास का नया उदाहरण बनाते हैं।
  4. विशेषताएँ जो पूरी कक्षा पर लागू होती हैं, उन्हें पहले परिभाषित किया जाता है, और उन्हें कक्षा की विशेषताएँ कहा जाता है
  5. विशेषताएँ जो किसी वर्ग (वस्तु) के विशिष्ट उदाहरण पर लागू होती हैं, उदाहरण विशेषताएँ कहलाती हैं। वे आम तौर पर __init__() अंदर परिभाषित होते हैं; यह आवश्यक नहीं है, लेकिन यह अनुशंसित है (चूंकि __init__() बाहर परिभाषित गुण __init__() परिभाषित किए जाने से पहले एक्सेस किए जाने के जोखिम को चलाते हैं)।
  6. कक्षा की परिभाषा में शामिल प्रत्येक विधि, अपने पहले पैरामीटर के रूप में प्रश्न में वस्तु को पारित करती है। इस पैरामीटर के लिए self शब्द का उपयोग किया जाता है ( self का उपयोग वास्तव में सम्मेलन द्वारा किया जाता है, क्योंकि self शब्द का पायथन में कोई अंतर्निहित अर्थ नहीं है, लेकिन यह पायथन के सबसे सम्मानित सम्मेलनों में से एक है, और आपको हमेशा इसका पालन करना चाहिए)।
  7. अन्य भाषाओं में ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग करने वाले लोग कुछ चीजों से आश्चर्यचकित हो सकते हैं। एक यह है कि पायथन में private तत्वों की कोई वास्तविक अवधारणा नहीं है, इसलिए सब कुछ, डिफ़ॉल्ट रूप से, C ++ / Java public कीवर्ड के व्यवहार का अनुकरण करता है। अधिक जानकारी के लिए, इस पृष्ठ पर "निजी वर्ग के सदस्य" उदाहरण देखें।
  8. कक्षा के कुछ तरीकों के निम्नलिखित रूप हैं: __functionname__(self, other_stuff) । ऐसे सभी तरीकों को "जादू के तरीके" कहा जाता है और पायथन में कक्षाओं का एक महत्वपूर्ण हिस्सा है। उदाहरण के लिए, पायथन में ऑपरेटर ओवरलोडिंग को जादुई तरीकों से लागू किया जाता है। अधिक जानकारी के लिए, संबंधित दस्तावेज़ देखें।

अब हम अपने Person वर्ग के कुछ उदाहरण प्रस्तुत करते हैं!

>>> # Instances
>>> kelly = Person("Kelly")
>>> joseph = Person("Joseph")
>>> john_doe = Person("John Doe")

वर्तमान में हमारे पास तीन Person वस्तुएं हैं, kelly , joseph , और john_doe

हम डॉट ऑपरेटर का उपयोग करके प्रत्येक उदाहरण से वर्ग की विशेषताओं तक पहुंच सकते हैं . फिर से ध्यान दें कि वर्ग और उदाहरण की विशेषताओं के बीच का अंतर:

>>> # Attributes
>>> kelly.species
'Homo Sapiens'
>>> john_doe.species
'Homo Sapiens'
>>> joseph.species
'Homo Sapiens'
>>> kelly.name
'Kelly'
>>> joseph.name
'Joseph'

हम उसी डॉट ऑपरेटर का उपयोग करके कक्षा के तरीकों को निष्पादित कर सकते हैं . :

>>> # Methods
>>> john_doe.__str__()
'John Doe'
>>>  print(john_doe)
'John Doe'
>>>  john_doe.rename("John")
'Now my name is John'

गुण

पायथन कक्षाएं गुणों का समर्थन करती हैं , जो नियमित ऑब्जेक्ट चर की तरह दिखती हैं, लेकिन कस्टम व्यवहार और प्रलेखन संलग्न करने की संभावना के साथ।

class MyClass(object):

    def __init__(self):
       self._my_string = ""
    
    @property
    def string(self):
        """A profoundly important string."""
        return self._my_string

    @string.setter
    def string(self, new_value):
        assert isinstance(new_value, str), \
               "Give me a string, not a %r!" % type(new_value)
        self._my_string = new_value

    @string.deleter
    def x(self):
        self._my_string = None

वर्ग MyClass की वस्तु के पास एक संपत्ति .string दिखाई देगी । हालांकि, यह व्यवहार अब कसकर नियंत्रित है:

mc = MyClass()
mc.string = "String!"
print(mc.string)
del mc.string

उपरोक्त सिंटैक्स के साथ-साथ उपयोगी सिंटैक्स के रूप में, प्रॉपर्टी सिंटैक्स उन विशेषताओं को जोड़ने के लिए सत्यापन, या अन्य संवर्द्धन की अनुमति देता है। यह सार्वजनिक एपीआई के साथ विशेष रूप से उपयोगी हो सकता है - जहां उपयोगकर्ता को मदद का एक स्तर दिया जाना चाहिए।

गुणों का एक और सामान्य उपयोग वर्ग को 'आभासी विशेषताओं' को पेश करने में सक्षम करना है - विशेषताएँ जो वास्तव में संग्रहीत नहीं हैं लेकिन केवल अनुरोध किए जाने पर गणना की जाती हैं।

class Character(object):
    def __init__(name, max_hp):
        self._name = name
        self._hp = max_hp
        self._max_hp = max_hp

    # Make hp read only by not providing a set method
    @property
    def hp(self):
        return self._hp

    # Make name read only by not providing a set method
    @property
    def name(self):
        return self.name

    def take_damage(self, damage):
        self.hp -= damage
        self.hp = 0 if self.hp <0 else self.hp

    @property
    def is_alive(self):
        return self.hp != 0

    @property
    def is_wounded(self):
        return self.hp < self.max_hp if self.hp > 0 else False

    @property
    def is_dead(self):
        return not self.is_alive

bilbo = Character('Bilbo Baggins', 100)
bilbo.hp
# out : 100
bilbo.hp = 200        
# out : AttributeError: can't set attribute
# hp attribute is read only.

bilbo.is_alive
# out : True
bilbo.is_wounded
# out : False
bilbo.is_dead
# out : False

bilbo.take_damage( 50 )

bilbo.hp
# out : 50

bilbo.is_alive
# out : True
bilbo.is_wounded
# out : True
bilbo.is_dead
# out : False

bilbo.take_damage( 50 )
bilbo.hp
# out : 0

bilbo.is_alive
# out : False
bilbo.is_wounded
# out : False
bilbo.is_dead
# out : True

एकल वर्ग

एक सिंगलटन एक ऐसा पैटर्न है जो एक वर्ग के तात्कालिकता को एक उदाहरण / वस्तु के लिए प्रतिबंधित करता है। अजगर सिंगलटन डिजाइन पैटर्न के बारे में अधिक जानकारी के लिए, यहां देखें।

class Singleton:
    def __new__(cls):
        try:
            it = cls.__it__
        except AttributeError:
            it = cls.__it__ = object.__new__(cls)
        return it

    def __repr__(self):
        return '<{}>'.format(self.__class__.__name__.upper())

    def __eq__(self, other):
         return other is self

एक और तरीका है अपनी कक्षा को सजाना। इस उत्तर से उदाहरण के बाद एक सिंगलटन वर्ग बनाएं:

class Singleton:
    """
    A non-thread-safe helper class to ease implementing singletons.
    This should be used as a decorator -- not a metaclass -- to the
    class that should be a singleton.

    The decorated class can define one `__init__` function that
    takes only the `self` argument. Other than that, there are
    no restrictions that apply to the decorated class.

    To get the singleton instance, use the `Instance` method. Trying
    to use `__call__` will result in a `TypeError` being raised.

    Limitations: The decorated class cannot be inherited from.

    """

    def __init__(self, decorated):
        self._decorated = decorated

    def Instance(self):
        """
        Returns the singleton instance. Upon its first call, it creates a
        new instance of the decorated class and calls its `__init__` method.
        On all subsequent calls, the already created instance is returned.

        """
        try:
            return self._instance
        except AttributeError:
            self._instance = self._decorated()
            return self._instance

    def __call__(self):
        raise TypeError('Singletons must be accessed through `Instance()`.')

    def __instancecheck__(self, inst):
        return isinstance(inst, self._decorated)

उपयोग करने के लिए आप Instance विधि का उपयोग कर सकते हैं

@Singleton
class Single:
    def __init__(self):
        self.name=None
        self.val=0
    def getName(self):
        print(self.name)

x=Single.Instance()
y=Single.Instance()
x.name='I\'m single'
x.getName() # outputs I'm single
y.getName() # outputs I'm single


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow