В чем разница между методами класса и экземпляра?

Вот несколько более сложная версия связанного класса списка, с похожим интерфейсом к типам последовательностей python (т. е. поддерживает индексирование, нарезку, конкатенацию с произвольными последовательностями и т. д.). Он должен иметь O (1) prepend, не копировать данные, если только это не требуется, и может использоваться довольно взаимозаменяемо с кортежами.

Это будет не так просто, как пространство или время, как lisp cons cells, так как классы python, очевидно, немного более тяжелы (вы можете немного улучшить ситуацию с помощью «__slots__ = '_head','_tail'», чтобы уменьшить использование памяти). Однако он будет иметь желаемые характеристики производительности.

Пример использования:

>>> l = LinkedList([1,2,3,4])
>>> l
LinkedList([1, 2, 3, 4])
>>> l.head, l.tail
(1, LinkedList([2, 3, 4]))

# Prepending is O(1) and can be done with:
LinkedList.cons(0, l)
LinkedList([0, 1, 2, 3, 4])
# Or prepending arbitrary sequences (Still no copy of l performed):
[-1,0] + l
LinkedList([-1, 0, 1, 2, 3, 4])

# Normal list indexing and slice operations can be performed.
# Again, no copy is made unless needed.
>>> l[1], l[-1], l[2:]
(2, 4, LinkedList([3, 4]))
>>> assert l[2:] is l.next.next

# For cases where the slice stops before the end, or uses a
# non-contiguous range, we do need to create a copy.  However
# this should be transparent to the user.
>>> LinkedList(range(100))[-10::2]
LinkedList([90, 92, 94, 96, 98])

Реализация:

import itertools

class LinkedList(object):
    """Immutable linked list class."""

    def __new__(cls, l=[]):
        if isinstance(l, LinkedList): return l # Immutable, so no copy needed.
        i = iter(l)
        try:
            head = i.next()
        except StopIteration:
            return cls.EmptyList   # Return empty list singleton.

        tail = LinkedList(i)

        obj = super(LinkedList, cls).__new__(cls)
        obj._head = head
        obj._tail = tail
        return obj

    @classmethod
    def cons(cls, head, tail):
        ll =  cls([head])
        if not isinstance(tail, cls):
            tail = cls(tail)
        ll._tail = tail
        return ll

    # head and tail are not modifiable
    @property  
    def head(self): return self._head

    @property
    def tail(self): return self._tail

    def __nonzero__(self): return True

    def __len__(self):
        return sum(1 for _ in self)

    def __add__(self, other):
        other = LinkedList(other)

        if not self: return other   # () + l = l
        start=l = LinkedList(iter(self))  # Create copy, as we'll mutate

        while l:
            if not l._tail: # Last element?
                l._tail = other
                break
            l = l._tail
        return start

    def __radd__(self, other):
        return LinkedList(other) + self

    def __iter__(self):
        x=self
        while x:
            yield x.head
            x=x.tail

    def __getitem__(self, idx):
        """Get item at specified index"""
        if isinstance(idx, slice):
            # Special case: Avoid constructing a new list, or performing O(n) length 
            # calculation for slices like l[3:].  Since we're immutable, just return
            # the appropriate node. This becomes O(start) rather than O(n).
            # We can't do this for  more complicated slices however (eg [l:4]
            start = idx.start or 0
            if (start >= 0) and (idx.stop is None) and (idx.step is None or idx.step == 1):
                no_copy_needed=True
            else:
                length = len(self)  # Need to calc length.
                start, stop, step = idx.indices(length)
                no_copy_needed = (stop == length) and (step == 1)

            if no_copy_needed:
                l = self
                for i in range(start): 
                    if not l: break # End of list.
                    l=l.tail
                return l
            else:
                # We need to construct a new list.
                if step < 1:  # Need to instantiate list to deal with -ve step
                    return LinkedList(list(self)[start:stop:step])
                else:
                    return LinkedList(itertools.islice(iter(self), start, stop, step))
        else:       
            # Non-slice index.
            if idx < 0: idx = len(self)+idx
            if not self: raise IndexError("list index out of range")
            if idx == 0: return self.head
            return self.tail[idx-1]

    def __mul__(self, n):
        if n <= 0: return Nil
        l=self
        for i in range(n-1): l += self
        return l
    def __rmul__(self, n): return self * n

    # Ideally we should compute the has ourselves rather than construct
    # a temporary tuple as below.  I haven't impemented this here
    def __hash__(self): return hash(tuple(self))

    def __eq__(self, other): return self._cmp(other) == 0
    def __ne__(self, other): return not self == other
    def __lt__(self, other): return self._cmp(other) < 0
    def __gt__(self, other): return self._cmp(other) > 0
    def __le__(self, other): return self._cmp(other) <= 0
    def __ge__(self, other): return self._cmp(other) >= 0

    def _cmp(self, other):
        """Acts as cmp(): -1 for self<other, 0 for equal, 1 for greater"""
        if not isinstance(other, LinkedList):
            return cmp(LinkedList,type(other))  # Arbitrary ordering.

        A, B = iter(self), iter(other)
        for a,b in itertools.izip(A,B):
           if a<b: return -1
           elif a > b: return 1

        try:
            A.next()
            return 1  # a has more items.
        except StopIteration: pass

        try:
            B.next()
            return -1  # b has more items.
        except StopIteration: pass

        return 0  # Lists are equal

    def __repr__(self):
        return "LinkedList([%s])" % ', '.join(map(repr,self))

class EmptyList(LinkedList):
    """A singleton representing an empty list."""
    def __new__(cls):
        return object.__new__(cls)

    def __iter__(self): return iter([])
    def __nonzero__(self): return False

    @property
    def head(self): raise IndexError("End of list")

    @property
    def tail(self): raise IndexError("End of list")

# Create EmptyList singleton
LinkedList.EmptyList = EmptyList()
del EmptyList
438
задан Josh Caswell 17 April 2013 в 02:50
поделиться

8 ответов

Как сказано в большинстве других ответов, методы экземпляра используют экземпляр класса, тогда как метод класса может использоваться только с именем класса. В Objective-C они определены следующим образом:

@interface MyClass : NSObject

+ (void)aClassMethod;
- (void)anInstanceMethod;

@end

Затем они могут использоваться следующим образом:

[MyClass aClassMethod];

MyClass *object = [[MyClass alloc] init];
[object anInstanceMethod];

Некоторые реальные примеры методов класса - это вспомогательные методы для многих классов Foundation, например NSString ] + stringWithFormat: или NSArray 's + arrayWithArray: . Методом экземпляра будет метод NSArray -count .

666
ответ дан 22 November 2019 в 23:09
поделиться

Методы класса не могут изменить или узнать значение любой переменной экземпляра. Это должно быть критерием для того, чтобы знать, может ли метод экземпляра быть методом класса.

1
ответ дан Deepee 17 April 2013 в 02:50
поделиться

В Objective-C все методы начинаются с символа «-» или «+». Пример:

@interface MyClass : NSObject
// instance method
- (void) instanceMethod;

+ (void) classMethod;
@end

Символы «+» и «-» указывают, является ли метод class method или instance method соответственно.

Разница была бы ясна, если бы мы назвали эти методы. Здесь методы объявлены в MyClass.

instance method требуется экземпляр класса:

MyClass* myClass = [[MyClass alloc] init];
[myClass instanceMethod];

Внутри MyClass другие методы могут вызывать методы экземпляра MyClass, используя self:

-(void) someMethod
{
    [self instanceMethod];
}

Но, class methods должен быть вызван для самого класса:

[MyClass classMethod];

Или:

MyClass* myClass = [[MyClass alloc] init];
[myClass class] classMethod];

Это не будет работать:

// Error
[myClass classMethod];
// Error
[self classMethod];
3
ответ дан Tulon 17 April 2013 в 02:50
поделиться

Методы класса обычно используются для создания экземпляров этого класса

Например, [NSString stringWithFormat:@"SomeParameter"]; возвращает экземпляр NSString с параметром, который ему отправляется. Следовательно, поскольку это метод класса, который возвращает объект своего типа, его также называют вспомогательным методом.

6
ответ дан animuson 17 April 2013 в 02:50
поделиться

Ответ на ваш вопрос не относится к объекту-c, однако на разных языках методы класса могут называться статическими методами.

Разница между методами класса и методами экземпляра

] Методы класса

  • Оперируют с переменными класса (они не могут получить доступ к переменным экземпляра)
  • Не требуют создания экземпляра объекта для применения
  • Иногда может быть запах кода (некоторые люди, которые плохо знакомы с ООП, используют как костыль для выполнения структурного программирования в объектно-ориентированной среде)

Методы экземпляра

  • Работа с переменными экземпляров и переменными класса
  • Должен иметь экземпляр объекта для работы с
15
ответ дан 22 November 2019 в 23:09
поделиться

Метод экземпляра применяется к экземпляру класса (т. Е. Объекту), тогда как метод класса применяется к самому классу.

В C # метод класса помечен как статический. Методы и свойства, не помеченные как статические, являются методами экземпляра.

class Foo {
  public static void ClassMethod() { ... }
  public void InstanceMethod() { ... }
}
36
ответ дан 22 November 2019 в 23:09
поделиться

Как уже говорилось в других ответах, методы экземпляра работают с объектом и имеют доступ к его переменным экземпляра, в то время как метод класса работает с классом в целом и не имеет доступа к конкретным переменным экземпляра (если только вы не передаете экземпляр в качестве параметра).

Хорошим примером метода класса является метод счетного типа, который возвращает общее количество экземпляров класса. Методы класса начинаются с + , а экземпляры - с - .

Хорошим примером метода класса является метод счетчика, который возвращает общее количество экземпляров класса. Методы класса начинаются с + , а экземпляры - с - .

Хорошим примером метода класса является метод счетчика, который возвращает общее количество экземпляров класса. Методы класса начинаются с + , а экземпляры - с - . Например:

static int numberOfPeople = 0;

@interface MNPerson : NSObject {
     int age;  //instance variable
}

+ (int)population; //class method. Returns how many people have been made.
- (id)init; //instance. Constructs object, increments numberOfPeople by one.
- (int)age; //instance. returns the person age
@end

@implementation MNPerson
- (id)init{
    if (self = [super init]){
          numberOfPeople++;
          age = 0;
    }    
    return self;
}

+ (int)population{ 
     return numberOfPeople;
}

- (int)age{
     return age;
}

@end

main.m:

MNPerson *micmoo = [[MNPerson alloc] init];
MNPerson *jon = [[MNPerson alloc] init];
NSLog(@"Age: %d",[micmoo age]);
NSLog(@"%Number Of people: %d",[MNPerson population]);

Вывод: Возраст: 0 Количество людей: 2

Другой пример: если у вас есть метод, который вы хотите, чтобы пользователь мог вызывать, иногда полезно сделать его методом класса. Например, если у вас есть класс с именем MathFunctions, вы можете сделать это:

+ (int)square:(int)num{ 
      return num * num;
}

Итак, тогда пользователь вызовет:

[MathFunctions square:34];

без необходимости создавать экземпляр класса!

Вы также можете использовать функции класса для возврата автоматически выпущенных объектов , например

+ (NSArray *)arrayWithObject:(id)object

NSArray, который берет объект, помещает его в массив и возвращает автоматически выпущенную версию массива, которая не требует управления памятью, отлично подходит для временных массивов и прочего.

Надеюсь, теперь вы понять, когда и / или почему вам следует использовать методы класса !!

102
ответ дан 22 November 2019 в 23:09
поделиться

Методы экземпляров работают с экземплярами классов (т. Е. «Объектами»). Методы классов связаны с классами (в большинстве языков для этих парней используется ключевое слово static ).

4
ответ дан 22 November 2019 в 23:09
поделиться